#!/usr/bin/env python3
import sys
from PyQt5.QtCore import *
from PyQt5.Qt import *  # noqa
from PyQt5.QtWidgets import (
    QAction, QApplication,  QMessageBox, QTextEdit, QMenu, QFileDialog)
from PyQt5.QtGui import QCursor, QFont, QColor, QPixmap, QTextCursor, QPalette
from PyQt5.QtPrintSupport import *

from PyQt5.Qsci import QsciLexerCPP, QsciScintilla, QsciAPIs, QsciScintillaBase
#from PyQt5.Qsci import QsciDocument
import keyword, yaml, easygui


class CodeEditor(QsciScintilla):

    def __init__(self, parent=None):
        super().__init__(parent)

        self.setUtf8(True)
        self.font = QFont()
        self.font.setFamily("Cascadia Code Light")
        self.font.setPointSize(13)
        self.font.setFixedPitch(True)
        self.setFont(self.font)

        self.fontmetrics = QFontMetrics(self.font)

        self.setFont(self.font)
        self.setMarginsFont(self.font)

        # set line number width
        self.setMarginWidth(0, self.fontmetrics.width(str(self.lines())) + 5)
        self.setMarginLineNumbers(0, True)

        # mesure line
        self.setEdgeMode(QsciScintilla.EdgeLine)
        self.setEdgeColumn(9000)
        self.setEdgeColor(QColor("#BBB8B5"))

        # brace match
        self.setBraceMatching(QsciScintilla.StrictBraceMatch)

        # current line color
        self.setCaretLineVisible(True)
        self.setCaretLineBackgroundColor(QColor("#2D2D2D"))
        self.setCaretForegroundColor(QColor("white"))

        # selection color

        self.setSelectionBackgroundColor(QColor("#606060"))
        self.setSelectionForegroundColor(QColor("#FFFFFF"))

        # table relative
        self.setIndentationsUseTabs(True)
        self.setIndentationWidth(5)
        self.setTabIndents(True)
        self.setAutoIndent(True)
        self.setBackspaceUnindents(True)
        self.setTabWidth(5)

        # indentation guides
        self.setIndentationGuides(True)

        # line number margin color
        self.setMarginsBackgroundColor(QColor("#272727"))
        self.setMarginsForegroundColor(QColor("#CCCCCC"))

        # folding margin
        self.setFolding(QsciScintilla.PlainFoldStyle)
        self.setMarginWidth(2, 12)
        # marker
        self.markerDefine(QsciScintilla.Minus,
                          QsciScintilla.SC_MARKNUM_FOLDEROPEN)
        self.markerDefine(QsciScintilla.Plus, QsciScintilla.SC_MARKNUM_FOLDER)
        self.markerDefine(QsciScintilla.Minus,
                          QsciScintilla.SC_MARKNUM_FOLDEROPENMID)
        self.markerDefine(QsciScintilla.Plus,
                          QsciScintilla.SC_MARKNUM_FOLDEREND)

        # marker define color
        self.setMarkerBackgroundColor(
            QColor("#FFFFFF"), QsciScintilla.SC_MARKNUM_FOLDEREND)
        self.setMarkerForegroundColor(
            QColor("#272727"), QsciScintilla.SC_MARKNUM_FOLDEREND)
        self.setMarkerBackgroundColor(
            QColor("#FFFFFF"), QsciScintilla.SC_MARKNUM_FOLDEROPENMID)
        self.setMarkerForegroundColor(
            QColor("#272727"), QsciScintilla.SC_MARKNUM_FOLDEROPENMID)
        self.setMarkerBackgroundColor(
            QColor("#FFFFFF"), QsciScintilla.SC_MARKNUM_FOLDERMIDTAIL)
        self.setMarkerForegroundColor(
            QColor("#272727"), QsciScintilla.SC_MARKNUM_FOLDERMIDTAIL)
        self.setMarkerBackgroundColor(
            QColor("#FFFFFF"), QsciScintilla.SC_MARKNUM_FOLDERTAIL)
        self.setMarkerForegroundColor(
            QColor("#272727"), QsciScintilla.SC_MARKNUM_FOLDERTAIL)
        self.setMarkerBackgroundColor(
            QColor("#FFFFFF"), QsciScintilla.SC_MARKNUM_FOLDERSUB)
        self.setMarkerForegroundColor(
            QColor("#272727"), QsciScintilla.SC_MARKNUM_FOLDERSUB)
        self.setMarkerBackgroundColor(
            QColor("#FFFFFF"), QsciScintilla.SC_MARKNUM_FOLDER)
        self.setMarkerForegroundColor(
            QColor("#272727"), QsciScintilla.SC_MARKNUM_FOLDER)
        self.setMarkerBackgroundColor(
            QColor("#FFFFFF"), QsciScintilla.SC_MARKNUM_FOLDEROPEN)
        self.setMarkerForegroundColor(
            QColor("#272727"), QsciScintilla.SC_MARKNUM_FOLDEROPEN)
        self.setFoldMarginColors(QColor("#272727"), QColor("#272727"))

        # whitespace
        self.setWhitespaceVisibility(QsciScintilla.WsInvisible)
        self.setWhitespaceSize(2)
        """
        the default margin is:
        0: line number,width is not zero
        1: width is zero
        2: folding, width is not zero
        """
        self.setMarginWidth(1, 0)

        # set lexer
        self.lexer = QsciLexerCPP(None)
        # load configure
        with open('highlights/default.yml', 'rb')as f:
            res = yaml.load(f, Loader=yaml.FullLoader)
        self.yml = res
        self.lexer.setFont(self.font)
        self.setLexer(self.lexer)
        # defult color
        self.lexer.setColor(QColor(res['cpp-defualt']['default']))
        # bg color
        self.lexer.setPaper(QColor(res['cpp-defualt']['background']))
        self.lexer.setColor(QColor(res['cpp-defualt']['keyword']), QsciLexerCPP.Keyword)
        # 文档注释 /**开头的颜色
        self.lexer.setColor(QColor(res['cpp-defualt']['comments']
          ['document']), QsciLexerCPP.CommentDoc)
        self.lexer.setColor(QColor(res['cpp-defualt']['comments']
          ['block']), QsciLexerCPP.Comment)  # 块注释 的颜色
        self.lexer.setColor(QColor(res['cpp-defualt']['comments']
          ['line']), QsciLexerCPP.CommentLine)  # 行注释的颜色
        self.lexer.setColor(QColor(res['cpp-defualt']['constants']
          ['number']), QsciLexerCPP.Number)  # 数字 的颜色
        self.lexer.setColor(QColor(res['cpp-defualt']['constants']
          ['char']),
                      QsciLexerCPP.DoubleQuotedString)  # 双引号字符串的颜色
        self.lexer.setColor(QColor(res['cpp-defualt']['constants']
          ['string']),
                      QsciLexerCPP.SingleQuotedString)  # 单引号字符的颜色
        self.lexer.setColor(QColor(res['cpp-defualt']['pre']), QsciLexerCPP.PreProcessor)  # 预编译语句的颜色
        self.lexer.setColor(QColor(res['cpp-defualt']['operator']), QsciLexerCPP.Operator) # 操作符的颜色
        # self.setColor(QColor("#000000"), QsciLexerCPP.Identifier)  #可识别字符的颜色，这个范围很广，包含了关键词，函数名；所以要取消这句
        self.lexer.setColor(QColor(res['cpp-defualt']['constants']
          ['unclosed']),
                      QsciLexerCPP.UnclosedString)  # 未完成输入的字符串的颜色
        font = self.font
        font.setItalic(True)
        self.lexer.setFont(font, QsciLexerCPP.Comment)  # 注释的字体用斜体

        # EOL parse
        for i in range(0, QsciScintillaBase.STYLE_MAX):
            desc = self.lexer.description(i)
            if desc:
                self.lexer.setEolFill(True, i)  # 将填充的底色延伸到屏幕的右端；否则默认只有文字的地方

        # high light code

        self.setMarginWidth(0, self.fontmetrics.width(str(self.lines())) + 5)
        self.linesChanged.connect(self.linesChange)

    def linesChange(self):
        self.setMarginWidth(0, self.fontmetrics.width(str(self.lines())) + 5)
